package com.helwen.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.EnumDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.databind.util.EnumResolver;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.helwen.constant.BaseEnum;
import com.helwen.constant.BaseEnumConverterFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;

import static com.helwen.constant.DateFormatters.local_datetime_formatter;


/**
 * @author heqiwen    jacksonObjectMapper对url请求参数处理与返回结果处理  这里处理枚举的逻辑是：
 * @version 1.0
 * @since 2020/11/4
 */
@Configuration
public class JacksonConfig {

    /*ObjectMapper（父类） ---- >   XmlMapper (子类)  和 JsonMapper (子类)
    XmlMapper  ：实现 对象 与 xml 之间的格式转换
    JsonMapper ：实现 对象 与 json 之间的格式转换*/
    @Bean
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
    {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        //JSON Long ==> String
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(local_datetime_formatter));
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(local_datetime_formatter));
        //序列化枚举，  因为每个枚举都继承了BaseEnum。
        simpleModule.addSerializer(BaseEnum.class, new JsonSerializer<BaseEnum>() {
            @Override
            public void serialize(BaseEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeObject(value.getValue());
            }
        });
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        /*
        * TODO 类型条件限定过宽且仅做了名称处理 ，这里处理枚举的反序列化。
        * */
        simpleModule.addDeserializer(Enum.class, new CommonDeserializer());
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }


    public static class CommonDeserializer extends JsonDeserializer implements ContextualDeserializer {
        private final Class<BaseEnum> aClass;
        private static BaseEnumConverterFactory baseEnumConverterFactory = BaseEnumConverterFactory.INSTANCE;
        public CommonDeserializer(Class<BaseEnum> aClass) {
            this.aClass = aClass;
        }

        public CommonDeserializer() {
            aClass = null;
        }

        @Override
        public BaseEnum deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
            if(StringUtils.isEmpty(jsonParser.getText())){
                return null;
            }
            return baseEnumConverterFactory.getConverter(aClass).convert(jsonParser.getText());
        }

        public JsonDeserializer createContextual(DeserializationContext ctx, BeanProperty property) throws JsonMappingException {
            Class rawCls = ctx.getContextualType().getRawClass();
            if(BaseEnum.class.isAssignableFrom(rawCls)){
                return new CommonDeserializer(rawCls);
            }
            return new EnumDeserializer(EnumResolver.constructFor((Class<Enum<?>>) rawCls, ctx.getConfig().getAnnotationIntrospector()),true);
        }
    }
}
